#pragma once

#include <cstring>
#include <cerrno>

#include <utility>
#include <map>
#include <queue>
#include <vector>
#include <string>
#include <atomic>
#include <chrono>
#include <functional>
#include <memory>

#include <pthread.h>

#include "log.hpp"
extern Log log;

#ifdef __TEST_DEBUG__
template<size_t MIN = 4, size_t MAX = 16>
#else
template<size_t MIN = 8, size_t MAX = 128>
#endif
class ThreadPool
{
private:
    typedef std::function<void(void)> task_type;
    typedef ThreadPool<MIN, MAX> self;
public:
    struct ThreadInfo
    {
        ThreadInfo(bool active = true, 
                    std::chrono::time_point<std::chrono::steady_clock> time = std::chrono::steady_clock::now())
            : _active(active)
            , _last_active(time)
        {}
        bool _active = true;
        std::chrono::time_point<std::chrono::steady_clock> _last_active;
    };
public:
    ThreadPool()
    {
        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&_cond, nullptr);
        pthread_cond_init(&_resize_cond, nullptr);
        pthread_cond_init(&_exit_cond, nullptr);
    }
private:
    ThreadPool(const self&) = delete;
    self& operator=(const self&) = delete;
public:
    static bool set_threadname(pthread_t tid, const std::string& name)
    {
        return pthread_setname_np(tid, name.substr(0, 15).c_str()) == 0;
    }
    static bool set_current_threadname(const std::string& name)
    {
        return set_threadname(pthread_self(), name);
    }
public:
    void start()
    {
        if (_is_running)
            return;
        
        _is_running = true;
        _alive_threads = 0;
        _idle_threads = 0;
        _init_threads = 0;
        _pending_exit = 0;
        
        for (size_t i = 0; i < MIN; ++i)
        {
            pthread_t tid;
            if (pthread_create(&tid, nullptr, worker, this) != 0)
                log(Log::Warning, "failed to create worker thread, errstring: %s", strerror(errno));
            _alive_threads++;
            _init_threads++;
            pthread_detach(tid);
        }
        
        // 启动管理线程
        pthread_create(&_manager_tid, nullptr, manager, this);
        pthread_detach(_manager_tid);
        
        log(Log::Info, "thread pool start success");
    }
    
    template<class... Args>
    void emplace(Args&&... args)
    {
        if (_is_running)
        {
            lock();
            _tasks.emplace(args...);
            wake_one();
            unlock();
        }
    }
    void push(const task_type& value)
    {
        emplace(value);
    }
    void push(task_type&& value)
    {
        emplace(std::forward<task_type>(value));
    }
    
    task_type& top()
    {
        return _tasks.front();
    }
    void pop()
    {
        _tasks.pop();
    }
    bool empty()
    {
        return _tasks.empty();
    }
    
    ~ThreadPool()
    {
        destroy();
    }
private:
    void lock()
    {
        pthread_mutex_lock(&_mtx);
    }
    void unlock()
    {
        pthread_mutex_unlock(&_mtx);
    }
    
    void wait()
    {
        pthread_cond_wait(&_cond, &_mtx);
    }
    void wake_one()
    {
        pthread_cond_signal(&_cond);
    }
    void wake_all()
    {
        pthread_cond_broadcast(&_cond);
    }
    
    void wake_manager()
    {
        pthread_cond_signal(&_resize_cond);
    }
    void manager_wait(int ms)
    {
        struct timespec ts;
        clock_gettime(CLOCK_REALTIME, &ts);
        ts.tv_nsec += ms * 1000000;
        // 处理纳秒溢出
        if (ts.tv_nsec >= 1000000000)
        {
            ts.tv_sec += ts.tv_nsec / 1000000000;
            ts.tv_nsec %= 1000000000;
        }
        pthread_cond_timedwait(&_resize_cond, &_mtx, &ts);
    }
    
    void thread_exit()
    {
        if (--_alive_threads == 0)
            pthread_cond_signal(&_exit_cond);
    }
    
    static void* worker(void* arg)
    {
        ThreadPool* pool = static_cast<ThreadPool*>(arg);
        pthread_t tid = pthread_self();
        set_current_threadname("t-worker");
#ifdef __TEST_DEBUG__
        log(Log::Debug, "work thread start, tid: %u", tid);
#endif
        pool->_idle_threads++;
        pool->_init_threads--;
        
        auto now = std::chrono::steady_clock::now();
        
        pool->lock();
        pool->_threads[tid] = {true, now};
        pool->unlock();
        
        while (true)
        {
            pool->lock();
            pool->_threads[tid]._last_active = std::chrono::steady_clock::now();
            // 等待任务或退出信号
            while (pool->_tasks.empty())
            {
                // 检查是否需要退出
                if (!pool->_threads[tid]._active)
                {
                    pool->_threads.erase(tid);
                    pool->_idle_threads--;
                    pool->_pending_exit--;
                    
                    // 通知可能等待的销毁线程
                    pool->thread_exit();
                    pool->unlock();
#ifdef __TEST_DEBUG__
                    log(Log::Debug, "work thread exit, tid: %u", tid);
#endif
                    return nullptr;
                }
                pool->wait();
                // 每次唤醒后更新活动时间
                pool->_threads[tid]._last_active = std::chrono::steady_clock::now();
            }
            
            task_type task = std::move(pool->top());
            pool->pop();
            pool->unlock();
            
            pool->_idle_threads--;
            pool->wake_manager();
            task();
            pool->_idle_threads++;
            pool->wake_manager();
        }
        return nullptr;
    }
    
    size_t calc_increase(size_t current_size, size_t idle_count) const
    {
        // 当线程数很少时，快速扩容
        if (current_size < MIN * 2)
            return std::min((MAX - current_size) / 2, MIN);
        
        // 基于空闲率计算增量
        double load_factor = 1.0 - static_cast<double>(idle_count) / current_size;
        size_t increment = 0;
        
        if (load_factor > 0.8)  // 高负载：扩容20%
            increment = static_cast<size_t>(current_size * 0.2);
        else if (load_factor > 0.6) // 中负载：扩容10%
            increment = static_cast<size_t>(current_size * 0.1);
        else
            increment = static_cast<size_t>(current_size * 0.05);
        
        // 确保最小增量为1，最大不超过剩余容量
        increment = std::max<size_t>(1, increment);
        return std::min(increment, MAX - current_size);
    }
    size_t calc_decrease(size_t current_size, size_t idle_count) const
    {
        // 计算空闲率
        double idle_ratio = static_cast<double>(idle_count) / current_size;
        size_t decrement = 0;
        
        // 高空闲率且线程数较多时缩容
        if (idle_ratio > 0.7 && current_size > MIN * 2) // 缩容比例基于空闲率
            decrement = static_cast<size_t>(current_size * (idle_ratio - 0.4));
        else if (idle_ratio > 0.6 && current_size > MIN)    // 中空闲率时保守缩容
            decrement = static_cast<size_t>(current_size * 0.3);
        
        // 确保最小减量为1，最大不超过安全限制
        decrement = std::max<size_t>(1, decrement);
        return std::min(decrement, current_size - MIN);
    }
    
    size_t get_available_size()
    {
        size_t alive = _alive_threads.load() - 1;
        size_t pend = _pending_exit.load();
        return alive - pend;
    }
    size_t get_available_idle()
    {
        int idle = _idle_threads.load();
        size_t pend = _pending_exit.load();
        return (idle > static_cast<int>(pend)) ? (idle - pend) : 0;
    }
    
    static void* manager(void* arg)
    {
        ThreadPool* pool = static_cast<ThreadPool*>(arg);
        set_current_threadname("t-manager");
        
        pool->lock();
        pool->_alive_threads++;
        log(Log::Info, "manage thread start, tid: %u", pool->_manager_tid);
        
        while (pool->_is_running)
        {
            // 在锁内检查所有条件
            size_t current_size = pool->get_available_size();
            size_t idle_count = pool->get_available_idle();
            
            // 检查扩容条件 检查init_thread以避免线程已申请但还未创建就再次扩容
            size_t increase = 0;
            if (pool->_init_threads == 0 && idle_count < 2 && current_size < MAX)
                increase = pool->calc_increase(current_size, idle_count);
            
            // 检查缩容条件
            size_t decrease = 0;
            std::vector<pthread_t> threads_to_deactivate;
            if (idle_count > current_size / 2 + 2 && current_size > MIN)
            {
                decrease = pool->calc_decrease(current_size, idle_count);
                log(Log::Info, "thread decrease, decrease: %u", decrease);
                if (decrease > 0)
                {
                    // 选择空闲时间最长的线程
                    auto cmp = [](const std::pair<pthread_t, ThreadInfo>& a, const std::pair<pthread_t, ThreadInfo>& b)
                                {
                                    return a.second._last_active > b.second._last_active;
                                };
                    
                    std::priority_queue<
                                        std::pair<pthread_t, ThreadInfo>,
                                        std::vector<std::pair<pthread_t, ThreadInfo>>,
                                        decltype(cmp)>
                                        candidates(cmp);
                    
                    for (const auto& pair : pool->_threads)
                    {
                        if (pair.second._active)
                            candidates.push(pair);
                    }
                    
                    // 执行缩容操作
                    size_t count = std::min<size_t>(decrease, candidates.size());
                    while (count-- > 0 && !candidates.empty())
                    {
                        auto tid = candidates.top().first;
                        candidates.pop();
                        pool->_threads[tid]._active = false;
                        pool->_pending_exit++;
                    }
                    // 唤醒可能被标记的线程
                    pool->wake_all();
                }
            }
            
            // 解锁进行创建线程(耗时)
            pool->unlock();
            
            // 执行扩容操作
            if (increase > 0)
            {
                log(Log::Info, "thread increase, increase: %u", increase);
                
                for (size_t i = 0; i < increase; ++i)
                {
                    pthread_t tid;
                    if (pthread_create(&tid, nullptr, worker, pool) != 0)
                        log(Log::Warning, "failed to create worker thread, errstring: %s", strerror(errno));
                    pool->_alive_threads++;
                    pool->_init_threads++;
                    pthread_detach(tid);
                }
                log(Log::Info, "thread expend success, aggregate: %d", current_size + increase);
            }
            
            // 重新加锁进行等待
            pool->lock();
            
            // 等待管理事件或超时
            pool->manager_wait(500);
        }
        
        // 管理器退出
        pool->thread_exit();
        pool->unlock();
        log(Log::Info, "manage thread exit, tid: %d", pool->_manager_tid);
        return nullptr;
    }
    
    void destroy()
    {
        if (!_is_running)
            return;
        
        _is_running = false;
        
        lock();
        // 标记所有线程退出
        for (auto& pair : _threads)
            pair.second._active = false;
        
        // 清空任务队列
        while (!empty())
            pop();
        
        // 唤醒所有线程
        wake_all();
        wake_manager();
        
        // 等待所有线程退出
        while (_alive_threads > 0)
            pthread_cond_wait(&_exit_cond, &_mtx);
        unlock();
        log(Log::Info, "thread all exit");
        
        // 清理资源
        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&_cond);
        pthread_cond_destroy(&_resize_cond);
        pthread_cond_destroy(&_exit_cond);
        
        log(Log::Info, "thread pool destory success");
    }
private:
    // 状态标志tasks
    std::atomic<bool> _is_running{false};
    
    // 线程管理
    std::map<pthread_t, ThreadInfo> _threads;
    std::atomic<size_t> _alive_threads{0};     // 创建线程数量
    std::atomic<size_t> _init_threads{0};     // 未启动线程数量
    std::atomic<size_t> _idle_threads{0};      // 空闲线程数量
    std::atomic<size_t> _pending_exit{0};  // 退出的线程数量
    
    // 任务队列
    std::queue<task_type> _tasks;
    
    // 管理器线程
    pthread_t _manager_tid;
    
    pthread_mutex_t _mtx;
    pthread_cond_t _cond;        // 任务可用通知
    pthread_cond_t _resize_cond; // 调整大小通知
    pthread_cond_t _exit_cond;   // 退出等待通知
};
